package com.changgou.oauth.service.impl;

import com.changgou.oauth.service.AuthService;
import com.changgou.oauth.util.AuthToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${auth.ttl}")
    Long ttl;

    /***
     * 登录方法
     * @param username 用户名
     * @param password 用户密码
     * @param clientId 客户端id
     * @param clientSecret 客户端密码
     * @return
     */
    @Override
    public AuthToken login(String username, String password, String clientId, String clientSecret) {

        //一.登录,获取jwt

        //2.构建请求路径 http://localhost:9200/oauth/token
        ServiceInstance serviceInstance = loadBalancerClient.choose("USER-AUTH");
        //uri = http://localhost:9200
        URI uri = serviceInstance.getUri();
        String url = uri + "/oauth/token";

        //3.构建请求头和请求体
        //3.1请求头
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Authorization", this.getHttpBasic(clientId, clientSecret));

        //3.2请求体
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type", "password");
        body.add("username", username);
        body.add("password", password);

        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);

        //后端401 400，不认为是异常，直接返回给前端
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
            //处理错误的方法
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401) {
                    //父类 处理错误的逻辑
                    super.handleError(response);
                }
            }
        });

        //1.向oauth接口发送请求
        //参数一.url
        //参数二.请求方法
        //参数三.请求头和体
        //参数四.返回值类型

        ResponseEntity<Map> responseMap = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);
        Map<String, String> map = responseMap.getBody();
        System.out.println(map);

        //二.结果封装
        //判断map 对不对
        if (map == null || map.get("access_token") == null || map.get("refresh_token") == null || map.get("jti") == null) {
            throw new RuntimeException("获取令牌失败!");
        }

        AuthToken authToken = new AuthToken();
        authToken.setAccessToken(map.get("access_token"));
        authToken.setRefreshToken(map.get("refresh_token"));
        authToken.setJti(map.get("jti"));

        //三.redis数据封装 jti:jwt
        //jwt 过期默认一小时 redis放的键值对也应该是一样的
        stringRedisTemplate.boundValueOps(authToken.getJti()).set(authToken.getAccessToken(), ttl, TimeUnit.SECONDS);

        return authToken;
    }

    /***
     * 退出方法
     * @param request
     * @param response
     */
    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals("uid")) {
                String jti = cookie.getValue();
                //设置cookie过期
                cookie.setMaxAge(0);
                response.addCookie(cookie);
                //删除缓存中的cookie
                stringRedisTemplate.delete(jti);
            }
        }
    }


    //请求头中Authorization值的计算方法
    private String getHttpBasic(String clientId, String clientSecret) {
        //Basic base64(客户端名称: 客户端密码)
        String str = clientId + ":" + clientSecret;
        byte[] encode = Base64Utils.encode(str.getBytes());
        return "Basic " + new String(encode);
    }
}
